
from typing import Any, Tuple, Union
from app.FileTypeEnum import FileTypeEnum, FolderStatusEnum
from app.models import *
from app.utils import create_file_token
from app.statusenum import *
from enum import Enum, unique, IntEnum

class DocCreateMethodEnum(Enum):
    """文档创建方式枚举类型
    """
    PROJECT_ID = "project_id"
    FOLDER_ID = "folder_id"

class FileretContentEnum(IntEnum):
    """
    我们约定该工具包下的函数返回以下三个数据：
    - ISSUCESS 为 False 时，代表出现了不应被忽略的严重错误
    - ERRINFO  为错误信息，正确执行时为None
    - DATA     为执行可达目的时返回的暴露出的数据，当中途出现可忽略的错误而无法执行时，该值为None
    """
    ISSUCESS = 0    # 不可忽略的内部错误
    ERRINFO = 1     # 可选用的错误信息
    DATA = 2        # 返回的数据


def get_fileret_content(ret:Tuple[bool, dict, Any], retindex :FileretContentEnum):
    return ret[retindex.value]

def checkfile_status(file: Files, allowRecycle: bool= False)->Tuple[bool, dict, Any]:
    """检查file model的内容的content 也是删除校验的底层函数

    暴露的数据：obj -- model对应内容的model (若为FOLDER或TEAM_ROOT，则返回文件 model本身)(不存在时为None)

    Arguments:
        file {Files} -- model
        allowRecycle {bool} -- 是否允许回收站内容

    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
        
    """
    if file.file_type == FileTypeEnum.FOLDER.value:
        allowStatus = [FolderStatusEnum.NORMAL.value]
        if allowRecycle:
            allowStatus.append(FolderStatusEnum.RECYCLE.value)
            pass

        if file.folder_status not in allowStatus:
            return True, {"errno": 3000, "msg": "文档已被删除"}, None

        return True, None, file

    elif file.file_type == FileTypeEnum.TEAM_ROOT.value:
        return True, None, file 

    elif file.file_type == FileTypeEnum.DOCUMENT.value:
        # 获得对应的唯一文档model
        try:
            doc = Documents.objects.get(doc_id=file.content_id)
        except Documents.DoesNotExist:
            return False, {"errno": 3001, "msg": "未知错误：文档不存在对应数据"}, None
        except Documents.MultipleObjectsReturned:
            return False, {"errno": 3002, "msg": "未知错误：文档存在多个对应数据"}, None

        allowStatus = [DocStatusEnum.NORMAL.value]
        if allowRecycle:
            allowStatus.append(DocStatusEnum.RECYCLE.value)
        
        if doc.doc_status not in allowStatus:
            return True, {"errno": 3003, "msg": "文档已被删除"}, None

        return True, None, doc

    elif file.file_type == FileTypeEnum.PROJECT.value:
        # 获得对应的唯一项目model
        try:
            project = Projects.objects.get(project_id=file.content_id)
        except Projects.DoesNotExist:
            return False, {"errno": 3004, "msg": "找不到该项目"}, None
        except Projects.MultipleObjectsReturned:
            return False, {"errno": 3005, "msg": "项目存在多个对应数据"}, None
        allowStatus = [ProjectStatusEnum.NORMAL.value]
        if allowRecycle:
            allowStatus.append(ProjectStatusEnum.RECYCLE.value)
        if project.project_status not in allowStatus:
            return True, {"errno": 3006, "msg": "项目已被删除"}, None

        return True, None, project
        
    else:
        return False, {"errno": 3007, "msg": "未知错误：文件类型错误"}, None


def checkdoc_privelige(user_id,doc_id,allowRecycle: bool= False) -> Tuple[bool, dict, Any]:
    """检查user_id是否有对应doc_id的权限

    暴露的数据： {"doc": doc, "teamtouser":teamtouser , "file": file}
    
    Arguments:
        user_id {int} -- 用户id
        doc_id {int} -- 文档id
        allowRecycle {bool} -- 是否允许回收站内容
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
        
    """
    # 由doc_id获得对应的文件model
    try:
        file = Files.objects.get(content_id=doc_id,file_type=FileTypeEnum.DOCUMENT.value)
    except Files.DoesNotExist:
        return False, {"errno": 3008, "msg": "找不到文档"}, None
    except Files.MultipleObjectsReturned:
        return False, {"errno": 3009, "msg": "未知错误：文档存在多个对应数据"}, None
    # 检查权限
    try:
        teamtouser = Teams2Users.objects.get(user_id=user_id, team_id=file.team_id)
    except Teams2Users.DoesNotExist:
        return True,{"errno": 3010, "msg": "您不是该文档所属团队的成员"}, None
    # 获得对应的文档model
    ret = checkfile_status(file=file, allowRecycle=allowRecycle)
    if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
        return False, get_fileret_content(ret, FileretContentEnum.ERRINFO),None
    elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
        return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
    doc = get_fileret_content(ret, FileretContentEnum.DATA)
    
    return True, None, {"doc": doc, "teamtouser":teamtouser , "file": file}


# def get_project_alldocs(project_id, allowRecycle: bool= False) -> Tuple[bool, dict, Any]:
#     """
#     ## 将废弃
#     获得对应项目的所有文档model (无身份验证, 校验删除状态)
#     暴露的数据：{"all_doc":all_doc, "all_doc_file": all_doc_file, "project_file": project_file, "project": project}
    
#     Arguments:
#         project_id {int} -- 项目id
#         allowRecycle {bool} -- 是否允许回收站内容,只对文档有效
#     Returns:
#         Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
#     """

#     try:
#         project_file = Files.objects.get(content_id=project_id, file_type=FileTypeEnum.PROJECT.value)
#     except Files.DoesNotExist:
#         return False, {"errno": 3011, "msg": "未知错误：找不到项目不存在对应目录"}, None
#     except Files.MultipleObjectsReturned:
#         return False, {"errno": 3012, "msg": "未知错误：项目存在多个对应目录"}, None

#     ret = __checkfile_status__(file=project_file)
#     if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
#         return False, get_fileret_content(ret, FileretContentEnum.ERRINFO),None
#     elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
#         return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
#     project = get_fileret_content(ret, FileretContentEnum.DATA)
    
#     all_doc_file = Files.objects.filter(parent_id=project_file.file_id, file_type=FileTypeEnum.DOCUMENT.value)
#     all_doc = []
#     for doc_file in all_doc_file:
#         ret = __checkfile_status__(file=doc_file, allowRecycle=allowRecycle)
#         if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
#             return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
#         elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
#             continue
#         doc = get_fileret_content(ret, FileretContentEnum.DATA)
#         all_doc.append(doc)
#     return True, None, {"all_doc":all_doc, "all_doc_file": all_doc_file, "project_file": project_file, "project": project}

    
def check_doc_create_valid(fileOrFileidToCreateIn: Union[int, str, Files]) -> Tuple[bool, dict, Any]:
    """检查文档创建的合法性  (排除在文档下创建等情况) (不校验删除状态)

    暴露的数据：file （上层容器的文件）

    Arguments:
        fileOrFileidToCreateIn {Union[int, str, Files]} -- 文档model或文档id
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]"""
    allow_type = [FileTypeEnum.TEAM_ROOT.value, FileTypeEnum.PROJECT.value, FileTypeEnum.FOLDER.value]
    disallow_type = [FileTypeEnum.DOCUMENT.value]
    if isinstance(fileOrFileidToCreateIn, int) or isinstance(fileOrFileidToCreateIn, str):
        try:
            file = Files.objects.get(file_id=fileOrFileidToCreateIn)
        except Files.DoesNotExist:
            return False, {"errno": 3013, "msg": "找不到目标目录"}, None
        except Files.MultipleObjectsReturned:
            return False, {"errno": 3014, "msg": "未知错误：存在多个对应目录"}, None
    elif isinstance(fileOrFileidToCreateIn, Files):
        file = fileOrFileidToCreateIn
    else:
        return False, {"errno": 3015, "msg": "未知错误：检查文档创建的合法性时类型错误"}, None
    if file.file_type in allow_type:
        return True, None, file
    elif file.file_type in disallow_type:
        return False, {"errno": 3016, "msg": "创建位置错误：不能在此创建文档"}, None
    else:
        return False, {"errno": 3017, "msg": "未知错误：文件类型错误"}, None

def get_filecontainer_alldocs(container_file_or_fileid: Union[int, str, Files], allowRecycle: bool= False) -> Tuple[bool, dict, Any]:
    """获得对应容器文件节点下的所有文档model (检查创建位置有效性，检验删除状态，无身份验证)
    暴露的数据：{"all_doc":all_doc, "all_doc_file": all_doc_file, "container_file": container_file, "container": container}

    (注意：team_root的container项为None)
    Arguments:
        container_file_or_fileid {Union[int, str, Files]} -- 容器文件或者容器文件id
        allowRecycle {bool} -- 是否允许回收站查询,只对容器文件下内容生效
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
    """
    ret = check_doc_create_valid(container_file_or_fileid)
    if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
        return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
    elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
        return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
    container_file = get_fileret_content(ret, FileretContentEnum.DATA)

    checkfile_status(file=container_file)
    if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
        return False, get_fileret_content(ret, FileretContentEnum.ERRINFO),None
    elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
        return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
    container = get_fileret_content(ret, FileretContentEnum.DATA)

    all_doc_file = Files.objects.filter(parent_id=container_file.file_id, file_type=FileTypeEnum.DOCUMENT.value)
    all_doc = []
    for doc_file in all_doc_file:
        ret = checkfile_status(file=doc_file, allowRecycle=allowRecycle)
        if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
            continue
        doc = get_fileret_content(ret, FileretContentEnum.DATA)
        all_doc.append(doc)
    return True, None, {"all_doc":all_doc, "all_doc_file": all_doc_file, "container_file": container_file, "container": container}

def get_content_data(obj: Union[Documents,Projects,Files], allowRecycle: bool= False)->Tuple[bool, dict, Any]:
    """获得model的标准格式化内容 （警告：没有任何校验，除files model本身对于对应内容的删除校验）

    支持的model：documents, projects, files
    
    暴露的数据：data
    
    （因为格式化原因，数据基本不暴露）

    Arguments:
        obj {Union[Documents,Projects,Files]} -- model
        allowRecycle {bool} -- 是否允许回收站查询
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
    """
    
    if isinstance(obj, Documents):
        doc = obj
        data = {
            "doc_id": doc.doc_id,
            "doc_name": doc.doc_name,
            "create_time": doc.create_time,
            "update_time": doc.update_time,
            "doc_status": doc.doc_status,
            "doc_token": create_file_token(str(doc.doc_id))
        }

        return True, None, data

    elif isinstance(obj, Projects):
        project = obj
        data = {
            "project_id": project.project_id,
            "project_name": project.project_name,
            "create_time": project.create_time,
            "update_time": project.update_time,
            "project_status": project.project_status
        }

        return True, None, data

    elif isinstance(obj, Files):
        file = obj
        ret = checkfile_status(obj, allowRecycle=allowRecycle)
        if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
            return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        model = get_fileret_content(ret, FileretContentEnum.DATA)
        detail = None
        if not isinstance(model,Files):
            retdata = get_content_data(model)
            if get_fileret_content(retdata, FileretContentEnum.ISSUCESS) == False:
                return False, get_fileret_content(retdata, FileretContentEnum.ERRINFO), None
            elif get_fileret_content(retdata, FileretContentEnum.DATA) == None:
                return True, get_fileret_content(retdata, FileretContentEnum.ERRINFO), None
            detail = get_fileret_content(retdata, FileretContentEnum.DATA)
        data = {
            "file_id": file.file_id,
            "parent_id": file.parent_id,
            "folder_name": file.folder_name,
            "file_type": file.file_type,
            "content_id": file.content_id,
            "team_id": file.team_id,
            "folder_status": file.folder_status,
            "detail": detail
        }

        return True, None, data

    else:
        return False, {"errno": 3018, "msg": "未知错误：文件类型错误"}, None

def check_file_privelige(file_or_fileid:Tuple[str,int,Files], user_id, allowRecycle: bool= False)->Tuple[bool, dict, Any]:
    """检查文件的team_id是否对应user_id参与团队 (含删除校验)
    
    暴露的数据：{"teamtouser":teamtouser , "file": file, "file_content": file_content}

    Arguments:
        - file_or_fileid {Tuple[str,int,Files]} -- [文件id或文件对象]
        - user_id {int} -- 用户id
        - allowRecycle {bool} -- 是否允许查看回收站
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
    """
    # 检查文件是否存在
    if isinstance(file_or_fileid, Files):
        file = file_or_fileid
    elif isinstance(file_or_fileid, str) or isinstance(file_or_fileid, int):
        try:
            file = Files.objects.get(file_id=file_or_fileid)
        except Files.DoesNotExist:
            return False, {"errno": 3019, "msg": "文件不存在"}, None
        except Files.MultipleObjectsReturned:
            return False, {"errno": 3020, "msg": "未知错误：多个同id文件"}, None
    else:
        return False, {"errno": 30201, "msg": "未知错误：内部参数类型错误"}, None
    # 检查文件是否被删除
    ret = checkfile_status(file, allowRecycle)
    if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
        return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
    elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
        return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
    file_content = get_fileret_content(ret, FileretContentEnum.DATA)


    # 检查权限
    try:
        teamtouser = Teams2Users.objects.get(user_id=user_id, team_id=file.team_id)
    except Teams2Users.DoesNotExist:
        return True,{"errno": 3021, "msg": "您不是该团队的成员"}, None
    
    return True, None, {"teamtouser":teamtouser , "file": file, "file_content": file_content}



def get_container_data(containerfile_or_fileid: Tuple[str,int,Files], allowRecycle: bool= False)->Tuple[bool, dict, Any]:
    """获得文件夹下所有内容的格式化数据(含删除检验/容器文件type检验，无身份验证)

    暴露的数据： {"containerfile": containerfile, "data": data, "all_files_incontainer": all_files_incontainer}

    Arguments:
        - containerfile_or_fileid {Tuple[str,int,Files]} -- [文件id或文件对象]
        - allowRecycle {bool} -- 是否允许查看回收站,仅对内部文件有效
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
        
    """
    allow_type = [FileTypeEnum.TEAM_ROOT.value, FileTypeEnum.PROJECT.value, FileTypeEnum.FOLDER.value]
    disallow_type = [FileTypeEnum.DOCUMENT.value]
    if(isinstance(containerfile_or_fileid, Files)):
        containerfile = containerfile_or_fileid
    elif(isinstance(containerfile_or_fileid, int) or isinstance(containerfile_or_fileid, str)):
        try:
            containerfile = Files.objects.get(file_id=containerfile_or_fileid)
        except Files.DoesNotExist:
            return False, {"errno": 3022, "msg": "目录不存在"}, None
        except Files.MultipleObjectsReturned:
            return False, {"errno": 3023, "msg": "未知错误：多个同id目录"}, None
    else:
        return False, {"errno": 30231, "msg": "未知错误：内部参数类型错误"}, None
    # 检查文件类型
    if containerfile.file_type in allow_type:
        pass
    elif containerfile.file_type in disallow_type:
        return False, {"errno": 3024, "msg": "文件类型错误"}, None
    else:
        return False, {"errno": 3025, "msg": "未知错误：文件类型错误"}, None


    # 获取parent_id为containerfile_id的所有文件
    __all_files_incontainer__ = Files.objects.filter(parent_id=containerfile.file_id)
    all_files_incontainer = []
    data = []
    for file in __all_files_incontainer__:
        ret = get_content_data(file, allowRecycle)
        if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
            continue
        data.append(get_fileret_content(ret, FileretContentEnum.DATA))
        all_files_incontainer.append(file)
    
    return True, None, {"containerfile": containerfile, "data": data, "all_files_incontainer": all_files_incontainer}
        
def check_folder_create_valid(fileOrFileidToCreateIn: Union[int, str, Files]) -> Tuple[bool, dict, Any]:
    """检查文件夹创建的合法性  (排除在文档下创建等情况) (不校验删除状态)

    暴露的数据：file （上层容器的文件）

    Arguments:
        fileOrFileidToCreateIn {Union[int, str, Files]} -- 文档model或文档id
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]"""
    allow_type = [FileTypeEnum.TEAM_ROOT.value, FileTypeEnum.FOLDER.value, FileTypeEnum.PROJECT.value]
    disallow_type = [FileTypeEnum.DOCUMENT.value]
    if isinstance(fileOrFileidToCreateIn, int) or isinstance(fileOrFileidToCreateIn, str):
        try:
            file = Files.objects.get(file_id=fileOrFileidToCreateIn)
        except Files.DoesNotExist:
            return False, {"errno": 3026, "msg": "找不到目标目录"}, None
        except Files.MultipleObjectsReturned:
            return False, {"errno": 3027, "msg": "未知错误：存在多个对应目录"}, None
    elif isinstance(fileOrFileidToCreateIn, Files):
        file = fileOrFileidToCreateIn
    else:
        return False, {"errno": 3028, "msg": "未知错误：检查文件夹创建的合法性时类型错误"}, None
    if file.file_type in allow_type:
        return True, None, file
    elif file.file_type in disallow_type:
        return False, {"errno": 3029, "msg": "不能在此创建文档"}, None
    else:
        return False, {"errno": 3030, "msg": "未知错误：文件类型错误"}, None

def get_teamroot_file(team_id) -> Tuple[bool, dict, Any]:
    """ 无校验 直接获取团队根目录文件model

    暴露的数据：teamroot_file 
    
    Arguments:
        team_id {int} -- 团队id
    Returns:
        Files -- 团队根目录文件model
    """
    try:
        teamroot_file = Files.objects.get(team_id=team_id, file_type=FileTypeEnum.TEAM_ROOT.value)
    except Files.DoesNotExist:
        return False, {"errno": 3031, "msg": "团队文件根目录不存在"}, None
    except Files.MultipleObjectsReturned:
        return False, {"errno": 3031, "msg": "未知错误：多个对应的团队文件根目录"}, None
    return True, None, teamroot_file

def get_parent_file(file: Files) -> Tuple[bool, dict, Any]:
    """ 无校验 直接获取父目录文件model
    
    暴露的数据：parent_file 
    
    Arguments:
        file {Files} -- 文件model
    Returns:
        Files -- 父目录文件model
    """
    try:
        parent_file = Files.objects.get(file_id=file.parent_id)
    except Files.DoesNotExist:
        return False, {"errno": 3032, "msg": "父目录不存在"}, None
    except Files.MultipleObjectsReturned:
        return False, {"errno": 3033, "msg": "未知错误：多个对应的父目录"}, None
    return True, None, parent_file

def check_existsfile_valid(fileOrFileid: Union[int, str, Files],fileOrFileidToCreateIn: Union[int, str, Files]) -> Tuple[bool, dict, Any]:
    """
        检测文件在移动到的新位置的合法性  (不校验删除状态)
        
        暴露的数据：{"file": file, "file_to_create_in": file_to_create_in}  

        Arguments:
            fileOrFileid {Union[int, str, Files]} -- 文件model或文件id
            fileOrFileidToCreateIn {Union[int, str, Files]} -- 文件model或文件id
        Returns:
            Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
    """
    if isinstance(fileOrFileid, int) or isinstance(fileOrFileid, str):
        try:
            file = Files.objects.get(file_id=fileOrFileid)
        except Files.DoesNotExist:
            return False, {"errno": 3034, "msg": "找不到目标文件"}, None
        except Files.MultipleObjectsReturned:
            return False, {"errno": 3035, "msg": "未知错误：存在多个对应文件"}, None
    elif isinstance(fileOrFileid, Files):
        file = fileOrFileid
    else:
        return False, {"errno": 3036, "msg": "未知错误：内部函数类型错误"}, None

    if isinstance(fileOrFileidToCreateIn, int) or isinstance(fileOrFileidToCreateIn, str):
        try:
            file_to_create_in = Files.objects.get(file_id=fileOrFileidToCreateIn)
        except Files.DoesNotExist:
            return False, {"errno": 3037, "msg": "找不到目标目录"}, None
        except Files.MultipleObjectsReturned:
            return False, {"errno": 3038, "msg": "未知错误：存在多个对应目录"}, None
    elif isinstance(fileOrFileidToCreateIn, Files):
        file_to_create_in = fileOrFileidToCreateIn
    else:
        return False, {"errno": 3039, "msg": "未知错误：内部函数类型错误"}, None

    if file.file_type == FileTypeEnum.DOCUMENT.value:

        ret = check_doc_create_valid(file_to_create_in)
        if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
            return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None

        return True, None, {"file": file, "file_to_create_in": file_to_create_in}

    elif file.file_type == FileTypeEnum.FOLDER.value:

        ret = check_folder_create_valid(file_to_create_in)
        if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
            return True, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        
        return True, None, {"file": file, "file_to_create_in": file_to_create_in}

    elif file.file_type == FileTypeEnum.TEAM_ROOT.value:
        return False, {"errno": 3040, "msg": "团队根目录不可更改"}, None
    elif file.file_type == FileTypeEnum.PROJECT.value:
        return False, {"errno": 3040, "msg": "项目目录不可更改"}, None
    else:
        return False, {"errno": 3041, "msg": "未知错误：文件类型错误"}, None

def check_is_ancestors(fileA: Files, fileB: Files) -> Tuple[bool, dict, Any]:
    """ 无条件检验 A是否是B的祖先
    
    暴露的数据：
    
    Arguments:
        file_to_create_in {Files} -- 文件model
    Returns:
        Tuple[bool, dict, Any] -- [不可忽略的内部错误，可选用的错误信息，返回的数据]
    """
    fileBstacklist = []
    is_ancestors = False
    if fileB.file_id == fileA.file_id:
        is_ancestors = True
        fileBstacklist.append(fileB)
        return True, None, {"is_ancestors": is_ancestors, "fileBstacklist": fileBstacklist}

    while fileB.parent_id != 0 and fileB.file_id != fileA.file_id:
        
        ret = get_parent_file(fileB)
        if get_fileret_content(ret, FileretContentEnum.ISSUCESS) == False:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        elif get_fileret_content(ret, FileretContentEnum.DATA) == None:
            return False, get_fileret_content(ret, FileretContentEnum.ERRINFO), None
        fileB = get_fileret_content(ret, FileretContentEnum.DATA)
        fileBstacklist.append(fileB)
        if fileB.file_id == fileA.file_id:
            is_ancestors = True
            break
    return True, None, {"is_ancestors": is_ancestors, "fileBstacklist": fileBstacklist}



def get_file_namestr_fromformat(file_format) -> Tuple[str,None]:
    """
        获取name字段，从被格式化的 get_content_data获得的obj (也是get_container_data列表内的obj)

        warning: 无条件，无任何校验
    """
    if file_format["file_type"] == FileTypeEnum.DOCUMENT.value:
        return file_format["detail"]["doc_name"]
    elif file_format["file_type"] == FileTypeEnum.FOLDER.value:
        return file_format["folder_name"]
    elif file_format["file_type"] == FileTypeEnum.PROJECT.value:
        return file_format["detail"]["project_name"]
    elif file_format["file_type"] == FileTypeEnum.TEAM_ROOT.value:
        return None
    else:
        raise Exception("file_format error")
def get_file_namestr_fromfile(file:Files, file_content) -> Tuple[str,None]:
    """
        从file model的获取对应的文件名字段
        
        warning: 无条件，无任何校验
    """
    if file.file_type == FileTypeEnum.DOCUMENT.value:
        return file_content.doc_name
    elif file.file_type == FileTypeEnum.FOLDER.value:
        return file.folder_name
    elif file.file_type == FileTypeEnum.PROJECT.value:
        return file_content.project_name
    elif file.file_type  == FileTypeEnum.TEAM_ROOT.value:

        return None
    else:
        raise Exception("file_format error")

def set_file_namestr_fromfile(file: Files, file_content, newname: str):
    """
        修改file model的对应的文件名字段, 并立即保存
        
        warning: 无条件，无任何校验
    """
    if file.file_type == FileTypeEnum.DOCUMENT.value:
        file_content.doc_name = newname
        file_content.save()
    elif file.file_type == FileTypeEnum.FOLDER.value:
        file.folder_name = newname
        file.save()
    elif file.file_type == FileTypeEnum.PROJECT.value:
        file_content.project_name = newname
        file_content.save()
    elif file.file_type  == FileTypeEnum.TEAM_ROOT.value:
        raise Exception("file_format error")
        #return None
    else:
        raise Exception("file_format error")

